#pragma once
#include"Common.hpp"
#include"Log.hpp"
#include"InetAddr.hpp"

namespace SocketModule
{
    using namespace LogModule;
    const static int gbacklog=16;
    
    class Socket
    {
        public:
        virtual ~Socket(){}
        virtual void SocketOrDie()=0;
        virtual void BindOrDie(uint16_t port)=0;
        virtual void ListenOrDie(int backlog)=0;
        virtual int Accept(InetAddr* client)=0;
        virtual void Close()=0;
        virtual int Recv(std::string* out)=0;
        virtual int Send(const std::string& message)=0;
        virtual int Connect(const std::string& server_ip,uint16_t port)=0;
        virtual int Fd()=0;

        //构建完整TCP本地服务
        void BuildTcpSocketMethod(uint16_t port,int backbag=gbacklog)
        {
            //初始化套接字
            SocketOrDie();
            //构建本地TCP服务
            BindOrDie(port);
            //设置监听数量
            ListenOrDie(backbag);
        }

        //构建服务端本地TCP服务
        void BuildTcpClientSocketMethod()
        {
            SocketOrDie();
        }
        // virtual ~Socket(){}
    };

    const static int defaultfd=-1;
    class TcpSocket:public Socket
    {
        public:
        TcpSocket():_sockfd(defaultfd)
        {}
        TcpSocket(int fd):_sockfd(fd)
        {}
        ~TcpSocket(){}

        //初始化套接字
        void SocketOrDie() override
        {
            _sockfd=socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {
                LOG(LogLevel::FATAL)<<"SOCKET ERROR";
                exit(SOCKET_ERR);
            }
            int opt=1;
            setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
            LOG(LogLevel::INFO)<<"SOCKET SUCCESS:"<<_sockfd;
        }

        //构建本地TCP服务
        void BindOrDie(uint16_t port)override
        {
            InetAddr locale_t(port);
            int n=bind(_sockfd,locale_t.NetAddrPtr(),locale_t.NetAddrLen());
            if(n<0)
            {
                LOG(LogLevel::FATAL)<<"BIND ERROR";
                exit(BIND_ERR);
            }
            LOG(LogLevel::INFO)<<"BIND SUCCESS";
        }

        //设置监听数量
        void ListenOrDie(int backlog)override
        {
            int n=listen(_sockfd,gbacklog);
            if(n<0)
            {
                LOG(LogLevel::FATAL)<<"LISTEN ERROR";
                exit(LISTEN_ERR);
            }
            LOG(LogLevel::INFO)<<"LISTEN SUCCESS";
        }

        #define ACCEPT_DONE -1
        #define ACCEPT_CONTINUE -2
        #define ACCEPT_ERR -3
        //连接客户端
        int Accept(InetAddr* client)override
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int fd=accept(_sockfd,CONV(peer),&len);
            if(fd<0)
            {
                if(errno==EAGAIN || errno==EWOULDBLOCK )
                {
                    return -1;
                }
                else if (errno==EINTR)
                {
                    return -2;
                }
                else
                {
                    LOG(LogLevel::WARNING)<<"ACCEPT ERROR";
                    return -3;
                }
                
            }
            client->SetAddr(peer);
            return fd;
        }

        //接收客户端数据
        int Recv(std::string* out)override
        {
            char buffer[4096*2];
            ssize_t n=recv(_sockfd,buffer,sizeof(buffer),0);
            if(n>0)
            {
                buffer[n]=0;
                *out+=buffer;
            }
            return n;
        }

        //发送数据给套接字对应的文件
        int Send(const std::string& message)override
        {
            return send(_sockfd,message.c_str(),message.size(),0);
        }

        //关闭套接字
        void Close()override
        {
            if(_sockfd>=0)
            {
                close(_sockfd);
            }
        }

        //客户端连接服务端
        int Connect(const std::string& server_ip,uint16_t port)
        {
            InetAddr inetaddr(server_ip,port);
            return connect(_sockfd,inetaddr.NetAddrPtr(),inetaddr.NetAddrLen());
        }

        //返回套接字
        int Fd() override
        {
            return _sockfd;
        }
        private:
        int _sockfd;
    };
}